<!DOCTYPE html>
<html>
  <head>
    <title>Receiver | Log to browser</title>
    <style>
      .block {
        position: relative;
        float: left;
        border: 1px rgb(128, 128, 128) solid;
      }
      .block.left {
        width: 69%;
      }
      .block.right {
        width: 20%;
        margin-left: 10px;
      }
      #messages {
        list-style-type: none;
        margin: 7px;
        padding: 5px;
        border: 1px black solid;
        font-family: "cascadia code";
        counter-reset: nline;
      }
      #messages > li {
        counter-increment: nline;
      }
      #messages > li > div ::before {
        content: counter(nline);
        margin-right: 7px;
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        font-size: smaller;
      }
      
      #messages > li > div > pre {
        margin: 0px;
        font-family: inherit;
      }
    </style>
  </head>
  <body>
    <h1>Logger to browser</h1>

    <div class="block left">
      <h4>Log messages:</h4>
      <ul id="messages"></ul>
    </div>
    <div class="block right">
      <h4>Attached process:</h4>
      <div id="processinfo"></div>
    </div>

    <script src="/socket.io/socket.io.js"></script>

    <script>
      var socket = io();

      function log(msg){
        function transitionJsonToString(jsonObj, callback) {
          var _jsonObj = null;
          if (Object.prototype.toString.call(jsonObj) !== "[object String]") {
            try {
              _jsonObj = JSON.stringify(jsonObj);
            } catch (error) {
              callback(error);
            }
          } else {
            try {
              jsonObj = jsonObj.replace(/(\')/g, '"');
              _jsonObj = JSON.stringify(JSON.parse(jsonObj));
            } catch (error) {
              callback(error);
            }
          }
          return _jsonObj;
        }
        function formatJson(jsonString, callback) {
          var reg = null;
          var formatted = "";
          var pad = 0;
          var PADDING = "    ";
          if (!jsonString) {
            return jsonString;
          }
          var _index = [];
          var _indexStart = null;
          var _indexEnd = null;
          var jsonArray = [];
          jsonString = jsonString.replace(/([\{\}])/g, "\r\n$1\r\n");
          jsonString = jsonString.replace(/([\[\]])/g, "\r\n$1\r\n");
          jsonString = jsonString.replace(/(\,)/g, "$1\r\n");
          jsonString = jsonString.replace(/(\r\n\r\n)/g, "\r\n");
          jsonString = jsonString.replace(/\r\n\,/g, ",");
          jsonArray = jsonString.split("\r\n");
          jsonArray.forEach(function (node, index) {
            var num = node.match(/\"/g) ? node.match(/\"/g).length : 0;
            if (num % 2 && !_indexStart) {
              _indexStart = index;
            }
            if (num % 2 && _indexStart && _indexStart != index) {
              _indexEnd = index;
            }
            if (_indexStart && _indexEnd) {
              _index.push({
                start: _indexStart,
                end: _indexEnd,
              });
              _indexStart = null;
              _indexEnd = null;
            }
          });
          _index.reverse().forEach(function (item, index) {
            var newArray = jsonArray.slice(item.start, item.end + 1);
            jsonArray.splice(
              item.start,
              item.end + 1 - item.start,
              newArray.join("")
            );
          });
          jsonString = jsonArray.join("\r\n");
          jsonString = jsonString.replace(/\:\r\n\{/g, ":{");
          jsonString = jsonString.replace(/\:\r\n\[/g, ":[");
          jsonArray = jsonString.split("\r\n");
          jsonArray.forEach(function (item, index) {
            console.log(item);
            var i = 0;
            var indent = 0;
            var padding = "";
            if (item.match(/\{$/) || item.match(/\[$/)) {
              indent += 1;
            } else if (
              item.match(/\}$/) ||
              item.match(/\]$/) ||
              item.match(/\},$/) ||
              item.match(/\],$/)
            ) {
              if (pad !== 0) {
                pad -= 1;
              }
            } else {
              indent = 0;
            }
            for (i = 0; i < pad; i++) {
              padding += PADDING;
            }
            formatted += padding + item + "\r\n";
            pad += indent;
          });
          return formatted.trim();
        }

        msg = formatJson(msg, () => {
          console.error("Error when formatting json.");
        });
        var messages = document.getElementById("messages");
        var item = document.createElement("li");
        var d = document.createElement("div");
        var t = document.createElement("pre");
        t.textContent = msg;
        d.appendChild(t);
        item.appendChild(d);
        messages.appendChild(item);
      }
      socket.on("log", function (msg) {
        log(msg);
      });
      socket.on("warn", function (msg) {
        log(msg);
      });
      socket.on("error", function (msg) {
        log(msg);
      });
      socket.on("attach", function (name) {
        var info = document.getElementById("processinfo");
        info.textContent = `Process "${name}" attached.`;
        info.style.color = "green";
      });

      socket.on("dettach", function () {
        var info = document.getElementById("processinfo");
        info.textContent = `No process attached.`;
        info.style.color = "grey";
      });

      var info = document.getElementById("processinfo");
      info.textContent = `No process attached.`;
      info.style.color = "grey";
    </script>
  </body>
</html>
